package cn.hh.ymcc.service.impl;

import cn.hh.ymcc.doc.CourseDoc;
import cn.hh.ymcc.domain.*;
import cn.hh.ymcc.dto.CourseDto;
import cn.hh.ymcc.dto.PreOrderDto;
import cn.hh.ymcc.enums.GlobalExceptionCode;
import cn.hh.ymcc.feign.CourseSearchFeignClient;
import cn.hh.ymcc.feign.MediaFeignClient;
import cn.hh.ymcc.mapper.CourseMapper;
import cn.hh.ymcc.result.JSONResult;
import cn.hh.ymcc.service.*;
import cn.hh.ymcc.util.AssertUtil;
import cn.hh.ymcc.vo.CourseDetailVo;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author huang.hao
 * @since 2025-04-24
 */
@Service
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {

    @Autowired
    private ITeacherService teacherService; // 讲师

    @Autowired
    private ICourseDetailService courseDetailService;  // 详情

    @Autowired
    private ICourseResourceService courseResourceService;  // 课程资源

    @Autowired
    private ICourseMarketService courseMarketService; // 课程销售

    @Autowired
    private ICourseChapterService courseChapterService; // 课程章节

    @Autowired
    private ICourseTeacherService courseTeacherService;  // 课程讲师

    @Autowired
    private ICourseTypeService courseTypeService;  // 课程类型

    @Autowired
    private ICourseSummaryService courseSummaryService; // 课程统计

    @Autowired
    private ICourseUserLearnService courseUserLearnService; // 课程用户

    @Autowired
    private CourseSearchFeignClient courseSearchFeignClient; // 注入Feign接口客户端

    @Autowired
    private MediaFeignClient mediaFeignClient;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    /**
     * 1.非空校验
     * 2.课程不能被注册
     * 3.保存数据
     *
     * @param dto
     */
    @Override
    @Transactional // 开启事务
    public void save(CourseDto dto) {
        Course course = dto.getCourse(); // 课程
        CourseDetail courseDetail = dto.getCourseDetail();
        CourseMarket courseMarket = dto.getCourseMarket();
        CourseResource courseResource = dto.getCourseResource();
        List<Long> teacharIds = dto.getTeacharIds();

        // 1.参数非空校验  JSR303

        // 2.课程不能被注册
        Course courseTmp = selectByName(course.getName());
        AssertUtil.isNull(courseTmp, "课程已被注册");

        // 3.保存课程
        // 做必要的参数的初始化  状态,讲师
        // 有些初始化的值,必须在service层做填写,方式被黑客黑了
        course.setStatus(Course.STATE_OFFLINE);
        // @TODO 后面做了登录之后来补充
        course.setLoginId(1L);
        course.setLoginUserName("yhptest1");
        // 获取到讲师,是一个List集合
        List<Teacher> teachers = teacherService.selectBatchIds(teacharIds);
        // stream流
        //
        StringBuilder sb = new StringBuilder();
        // for循环获取到所有讲师的名字,使用StringBuilder,拼接多个讲师名,用,号隔开
        teachers.forEach(teacher -> {
            sb.append(teacher.getName()).append(",");
        });
        // 设置讲师名字为获取到的讲师名
        course.setTeacherNames(sb.toString());
        // 保存课程
        insert(course);

        // 保存课程详细
        courseDetail.setId(course.getId()); // 课程详细id和课程id保持一致
        courseDetailService.insert(courseDetail);

        // 保存课程销售
        courseMarket.setId(course.getId());
        courseMarketService.insert(courseMarket);

        // 保存课程讲师
        teacharIds.forEach(id -> {
            // 创建一个CourseTeacher课程讲师对象
            CourseTeacher courseTeacher = new CourseTeacher();
            courseTeacher.setCourseId(course.getId());  // 课程讲师对象设置课程id为course.getId
            courseTeacher.setTeacherId(id);   // 课程讲师对象设置id为teacharIds里遍历到的id
            courseTeacherService.insert(courseTeacher); // 保存courseTeacher
        });
//        courseTeacherService.insertBatch(courseTeacher);

        // 保存课程资源
        courseResource.setCourseId(course.getId());
        courseResourceService.insert(courseResource);

        // 初始化课程统计
        // 创建一个CourseSummary对象
        CourseSummary courseSummary = new CourseSummary();
        courseSummary.setId(course.getId());
        courseSummaryService.insert(courseSummary);

        // 课程类型表中的课程数+1
        CourseType type = courseTypeService.selectById(course.getCourseTypeId());
        type.setTotalCount(type.getTotalCount() + 1);
        courseTypeService.updateById(type);
    }

    /**
     * 课程上架
     *
     * @param courseId
     */
    @Override
    @Transactional // 开启事务
    public void onLineCourse(Long courseId) {
        // 判断课程id是否为空
        AssertUtil.isNotNull(courseId, GlobalExceptionCode.SERVICE_PARAM_IS_NULL.getMessage());
        // 1.根据课程Id查询课程,判断课程是否存在
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course, "课程不存在!");
        boolean offLine = course.getStatus() == Course.STATE_OFFLINE;
        AssertUtil.isTrue(offLine, "课程已上线,请不要重复上线");

        // 2.修改课程状态为上架,填写上架时间
        course.setStatus(Course.STATE_ONLINE); // 1:上架 0:下架
        course.setOnlineTime(new Date()); // 设置上架时间
        updateById(course); // 修改课程状态为上线

        // 3.保存课程相关内容到Es
        // 3.1为service-search编写feign接口 ymcc-api-search
        // 3.2在课程微服务中,依赖feign接口
        // 3.3使用feign远程调用search完成课程保存到Es中 [Search需要写一个Controller接口]
        CourseType type = courseTypeService.selectById(course.getCourseTypeId()); // 查出CourseType表中的id
        CourseMarket courseMarket = courseMarketService.selectById(course.getId()); // 查出CourseMarket表中的id
        CourseSummary courseSummary = courseSummaryService.selectById(course.getId()); // 查出CCourseSummary表中的id
        CourseDoc doc = new CourseDoc(); // 创建一个空的Es文档对象
        // 设置需要保存到Es的字段   调用BeanUtils的copy方法
        BeanUtils.copyProperties(course, doc);  // copyProperties(数据源,目标)
        BeanUtils.copyProperties(courseMarket, doc);  // copyProperties(数据源,目标)
        BeanUtils.copyProperties(courseSummary, doc);  // copyProperties(数据源,目标)
        doc.setCourseTypeName(type.getName()); // 这里要单独赋值,否则上面拷贝的时候会将name覆盖
        String chargeName = courseMarket.getCharge() == 1 ? "免费" : "收费"; // 使用三元运算符判断courseMarket的Charge字段
        doc.setChargeName(chargeName); // 将判断后的chargeName,设置进Es文档对象

        // 使用注入的feign接口调用添加方法,将doc传入
        JSONResult result = courseSearchFeignClient.saveCourse(doc);
        AssertUtil.isTrue(result.isSuccess(), "课程发布失败");
    }

    /**
     * 下架课程
     *
     * @param courseId
     */
    @Override
    @Transactional
    public void offLineCourse(Long courseId) {
        // 1.根据课程Id查询课程
        Course course = selectById(courseId);
        // 断言课程必须存在
        AssertUtil.isNotNull(course, "查询课程出错!");

        // 校验课程是否已经是下架状态
        boolean offLineCourse = course.getStatus() == Course.STATE_ONLINE;
        AssertUtil.isTrue(offLineCourse, "课程已经被下架,请勿重复下架!!");

        // 修改状态为下架
        course.setStatus(Course.STATE_OFFLINE);
        updateById(course); // 修改

        //  使用feign远程调用search将Es中的课程删除 [Search需要写一个Controller接口]
        // 使用注入的feign接口调用删除方法,将课程对象course传入  删除Es中的课程
        JSONResult jsonResult = courseSearchFeignClient.deleteByIdCourse(course.getId());
        AssertUtil.isTrue(jsonResult.isSuccess(), "课程删除失败!");


    }

    /**
     * 查询课程详细
     *
     * @param courseId
     */
    @Override
    public JSONResult getDetail(Long courseId) {
        // 空值校验
        AssertUtil.isNotNull(courseId, GlobalExceptionCode.SERVICE_PARAM_IS_NULL.getMessage());
        // 业务校验 查询课程是否存在
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course, GlobalExceptionCode.COURSE_IS_NULL_ERROR.getMessage());
        AssertUtil.isTrue(course.getStatus() == Course.STATE_ONLINE, GlobalExceptionCode.COURSE_STATUS_ERROR.getMessage());
        // 查询课程相关数据
        CourseDetailVo courseDetailVo = new CourseDetailVo();
        CourseDetail courseDetail = courseDetailService.selectById(courseId);
        CourseMarket courseMarket = courseMarketService.selectById(courseId);
        CourseSummary courseSummary = courseSummaryService.selectById(courseId);
        // 查询课程讲师
        Wrapper<CourseTeacher> wrapper = new EntityWrapper<>();
        List<CourseTeacher> list = courseTeacherService.selectList(wrapper.eq("course_id", courseId));
        List<Long> ids = list.stream().map(CourseTeacher::getTeacherId).collect(Collectors.toList());
        List<Teacher> teachers = teacherService.selectBatchIds(ids);
        // 调用media-feign接口查询章节视频
        // 查询课程章节
        List<CourseChapter> courseChapters = courseChapterService.listByCourseId(courseId);
        Map<Long, CourseChapter> courseChapterMap = courseChapters.stream().collect(Collectors.toMap(CourseChapter::getId, item -> item));
        // 调用media服务查询视频
        JSONResult jsonResult = mediaFeignClient.queryMediaByCourseId(courseId);
        AssertUtil.isTrue(jsonResult.isSuccess(), GlobalExceptionCode.SERVICE_ERROR.getMessage());
        if (jsonResult.getData() != null) {
            // 将json字符串转换为list集合
            List<MediaFile> mediaFiles = JSON.parseArray(jsonResult.getData().toString(), MediaFile.class);
            // 遍历视频查询出章节下的视频
            mediaFiles.forEach(e -> {
                e.setFileUrl("");
                CourseChapter courseChapter = courseChapterMap.get(e.getChapterId());
                if (courseChapter != null) {
                    courseChapter.getMediaFiles().add(e);
                }
            });
        }
        courseDetailVo.setCourse(course);
        courseDetailVo.setCourseChapters(courseChapters);
        courseDetailVo.setCourseDetail(courseDetail);
        courseDetailVo.setCourseMarket(courseMarket);
        courseDetailVo.setCourseSummary(courseSummary);
        courseDetailVo.setTeachers(teachers);
        return JSONResult.success(courseDetailVo);

    }

    /**
     * 获取视频播放
     *
     * @param mediaId
     * @return 当用户点击某个视频的时候，发请求到后台拿取视频地址，
     * 后台需要查询 hrm-course库中的`t_course_user_lean` 表来确定用户是否有购买该课程
     */
    @Override
    public String getForUser(Long mediaId) {
        // 非空校验mediaId
        AssertUtil.isNotNull(mediaId, GlobalExceptionCode.SERVICE_PARAM_IS_NULL.getMessage());
        // 通过media的feign接口提供的方法传入mediaId获取到jsonResult对象
        JSONResult jsonResult = mediaFeignClient.get(mediaId);
        // 判断jsonResult对象是否存在
        AssertUtil.isNotNull(jsonResult.getData(), GlobalExceptionCode.MEDIA_IS_ERROR.getMessage());
        // 使用JSONObject调用方法将获取到的jsonResult对象转换成mediaFile对象
        //   MediaFile mediaFile = JSON.parseObject(jsonResult.getData().toString(), MediaFile.class);
        MediaFile mediaFile = JSON.parseObject(JSON.toJSONString(jsonResult.getData()), MediaFile.class);
//        String string = jsonResult.getData().toString();
//        MediaFile mediaFile = JSON.parseObject(string, MediaFile.class);
        // 使用mediaFile对象判断课程视频是否为免费, 免费就返回视频地址
        if (mediaFile.getFree()) {
            return mediaFile.getFileUrl();
        }
        // 判断用户是否购买了课程视频，如果没购买，提示去购买，如果购买了返回视频地址，提供给用户播放
        // 获取到用户对象
//        CourseUserLearn courseUserLearn = courseUserLearnService.selectById(mediaId);
////        // 非空校验
//       AssertUtil.isNotNull(courseUserLearn,GlobalExceptionCode.SERVICE_PARAM_IS_NULL.toString());
        // 查询用户是否购买课程视频
        Long loginId = 1L;
        Wrapper<CourseUserLearn> wrapper = new EntityWrapper<>();
        wrapper.eq("login_id", loginId);
        wrapper.eq("course_id", mediaFile.getCourseId());
        CourseUserLearn courseUserLearn = courseUserLearnService.selectOne(wrapper);
        AssertUtil.isNotNull(courseUserLearn, GlobalExceptionCode.COURSE_WATCH_ERROR.getMessage());
        // 检验课程是否过期
        boolean before = new Date().before(courseUserLearn.getEndTime());
        AssertUtil.isTrue(before, GlobalExceptionCode.COURSE_EXPIRED_ERROR.getMessage());
        return mediaFile.getFileUrl();
    }

    /**
     * 获取订单信息
     * 确认订单页需要把课程数据回显
     *
     * @param courseIds
     * @return
     */
    @Override
    public JSONResult info(String courseIds) {
        // 判断课程Id是否为空
        AssertUtil.isNotNull(courseIds, GlobalExceptionCode.SERVICE_PARAM_IS_NULL.getMessage());
        // 查询课程id获取到课程对象
        Course course = selectById(courseIds);
        // 判断课程对象是否为空
        AssertUtil.isNotNull(course, GlobalExceptionCode.COURSE_IS_NULL_ERROR.getMessage());

        // 创建courseDto
        CourseDto courseDto = new CourseDto();
        // 将course设置进courseDto对象中
        courseDto.setCourse(course);

        // 获取课程详细courseDetail
        CourseDetail courseDetail = courseDetailService.selectById(courseIds);
        // 校验获取到的courseDetail是否为空
        AssertUtil.isNotNull(courseDetail, GlobalExceptionCode.SERVICE_PARAM_IS_NULL.getMessage());
        courseDto.setCourseDetail(courseDetail);

        // 获取课程销售CourseMarket
        CourseMarket courseMarket = courseMarketService.selectById(courseIds);
        // 校验获取到的courseMarket  是否为空
        AssertUtil.isNotNull(courseMarket, GlobalExceptionCode.SERVICE_PARAM_IS_NULL.getMessage());

        // 设置价格
        courseDto.setTotalAmount(courseMarket.getPrice());
        courseDto.setCourseMarket(courseMarket);

        // 获取课程资源对象CourseResource
        CourseResource courseResource = courseResourceService.selectById(courseIds);
        // 校验获取到的courseResource是否为空
        AssertUtil.isNotNull(courseResource, GlobalExceptionCode.SERVICE_PARAM_IS_NULL.getMessage());
        courseDto.setCourseResource(courseResource);


//        // 获取课程讲师teacharIds
//        Wrapper<CourseTeacher> wrapper = new EntityWrapper<>();
//        wrapper.eq("course_id",courseIds);
//        List<CourseTeacher> teachers = courseTeacherService.selectList(wrapper);
//        // 校验获取到的courseTeacher是否为空
//        AssertUtil.isNotNull(teachers,GlobalExceptionCode.SERVICE_PARAM_IS_NULL.getMessage());
//        List<Long> longs = new ArrayList<>();
//        for (CourseTeacher teacher : teachers) {
//            longs.add(teacher.getTeacherId());
//        }
//        courseDto.setTeacharIds(longs);

        List<CourseDto> courses = new ArrayList<>();
        courses.add(courseDto);
        return JSONResult.success(courses);
    }


    /**
     *  后端调用
     * @param courseIds
     * @return
     */
    @Override
    public JSONResult rpcInfo(String courseIds) {
        // 判断课程Id是否为空
        AssertUtil.isNotNull(courseIds, GlobalExceptionCode.SERVICE_PARAM_IS_NULL.getMessage());
        // 查询课程id获取到课程对象
        Course course = selectById(courseIds);
        // 判断课程对象是否为空
        AssertUtil.isNotNull(course, GlobalExceptionCode.COURSE_IS_NULL_ERROR.getMessage());

        // 创建courseDto
        CourseDto courseDto = new CourseDto();
        // 将course设置进courseDto对象中
        courseDto.setCourse(course);

        // 获取课程详细courseDetail
        CourseDetail courseDetail = courseDetailService.selectById(courseIds);
        // 校验获取到的courseDetail是否为空
        AssertUtil.isNotNull(courseDetail, GlobalExceptionCode.SERVICE_PARAM_IS_NULL.getMessage());
        courseDto.setCourseDetail(courseDetail);

        // 获取课程销售CourseMarket
        CourseMarket courseMarket = courseMarketService.selectById(courseIds);
        // 校验获取到的courseMarket  是否为空
        AssertUtil.isNotNull(courseMarket, GlobalExceptionCode.SERVICE_PARAM_IS_NULL.getMessage());

        // 设置价格
        courseDto.setTotalAmount(courseMarket.getPrice());
        courseDto.setCourseMarket(courseMarket);

        // 获取课程资源对象CourseResource
        CourseResource courseResource = courseResourceService.selectById(courseIds);
        // 校验获取到的courseResource是否为空
        AssertUtil.isNotNull(courseResource, GlobalExceptionCode.SERVICE_PARAM_IS_NULL.getMessage());
        courseDto.setCourseResource(courseResource);


        List<CourseDto> courses = new ArrayList<>();
        courses.add(courseDto);
        String jsonString = JSON.toJSONString(courses);
        return JSONResult.success(jsonString);

//        List<CourseDto> courses = new ArrayList<>();
//        courses.add(courseDto);
//        return JSONResult.success(courses);
    }

    /**
     *  查询秒杀订单结算页详细
     * @param orderNo
     * @return
     */
    @Override
    public JSONResult oneByOrder(String orderNo) {
        // 从redis中查出订单号获取对象
        Object tmp = redisTemplate.opsForValue().get(orderNo);
        // 校验订单号对象是否存在
       AssertUtil.isNotNull(tmp,GlobalExceptionCode.ORDER_IS_NULL_ERROR.getMessage());
        // 将订单号对象tmp强转为PreOrderDto类型,获取preOrderDto对象
        PreOrderDto preOrderDto = (PreOrderDto)tmp;
        // 查询preOrderDto中的秒杀课程,获取到秒杀课程对象
        Course course = selectById(preOrderDto.getCourseId());
        // 创建一个空的CourseDto对象
        CourseDto courseDto = new CourseDto();
        courseDto.setCourse(course);

        // 查询秒杀课程courseId,获取到课程销售对象
        CourseMarket market = courseMarketService.selectById(course.getId());
        market.setPrice(preOrderDto.getTotalAmount()); // 给课程销售对象设置秒杀价格
        courseDto.setCourseMarket(market); // 将课程销售对象设置进课程对象dto

        // 查询秒杀课程courseId,获取到课程详情对象
        CourseDetail courseDetail1 = courseDetailService.selectById(course.getId());
        courseDto.setCourseDetail(courseDetail1);

        // 查询秒杀课程courseId,获取到课程资源对象
        CourseResource courseResource1 = courseResourceService.selectById(course.getId());
        courseDto.setCourseResource(courseResource1);

        courseDto.setTotalAmount(preOrderDto.getTotalAmount()); // 设置总金额

        List<CourseDto> courses = new ArrayList<>();
        courses.add(courseDto);

        return JSONResult.success(courses);
    }

    /**
     * 查询课程
     * @param name 通过name查询课程
     * @return
     */
    private Course selectByName(String name) {
        Wrapper<Course> tWrapper = new EntityWrapper<Course>();
        tWrapper.eq("name", name);
        return selectOne(tWrapper);

    }
}
